package com.yubest.fs.service.impl;

import com.yubest.fs.bean.*;
import com.yubest.fs.config.FileStorageProperties;
import com.yubest.fs.service.Storage;
import com.yubest.fs.util.FileUtil;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;

/**
 * 文件处理器，父类
 * @Author hweiyu
 * @Description
 * @Date 2022/2/9 14:18
 */
public abstract class AbstractStorage<T> implements Storage {

    /**
     * 配置文件信息
     */
    private FileStorageProperties props;

    /**
     * 文件处理客户端
     */
    private ThreadLocal<T> client = new ThreadLocal<>();

    /**
     * 上传
     * @param request
     * @return
     */
    @Override
    public PutResponse put(PutFileRequest request) {
        prepareClient(request.getBucket());
        try {
            return upload(request);
        } catch (Exception e) {
            throw e;
        } finally {
            closeClient();
        }
    }

    /**
     * 下载
     * @param request
     * @return
     */
    @Override
    public FileStream get(GetFileRequest request) {
        prepareClient(request.getBucket());
        try {
            return download(request);
        } catch (Exception e) {
            throw e;
        } finally {
            closeClient();
        }
    }

    /**
     * 获取访问链接
     * @param request
     * @return
     */
    @Override
    public String getUrl(GetFileRequest request) {
        prepareClient(request.getBucket());
        try {
            return getAccessUrl(request);
        } catch (Exception e) {
            throw e;
        } finally {
            closeClient();
        }
    }

    /**
     * 获取文件元数据
     * @param request
     * @return
     */
    @Override
    public FileMeta getMeta(GetFileRequest request) {
        prepareClient(request.getBucket());
        try {
            return doGetMeta(request);
        } catch (Exception e) {
            throw e;
        } finally {
            closeClient();
        }
    }

    @Override
    public boolean isExists(GetFileRequest request) {
        prepareClient(request.getBucket());
        try {
            return isFileExists(request);
        } catch (Exception e) {
            throw e;
        } finally {
            closeClient();
        }
    }

    /**
     * 删除
     * @param request
     * @return
     */
    @Override
    public boolean remove(RemoveFileRequest request) {
        prepareClient(request.getBucket());
        try {
            return delete(request);
        } catch (Exception e) {
            throw e;
        } finally {
            closeClient();
        }
    }

    public abstract PutResponse upload(PutFileRequest request);

    public abstract FileStream download(GetFileRequest request);

    public abstract String getAccessUrl(GetFileRequest request);

    public abstract FileMeta doGetMeta(GetFileRequest request);

    public abstract boolean isFileExists(GetFileRequest request);

    public abstract boolean delete(RemoveFileRequest request);

    /**
     * 获取文件路径
     * @param prefix
     * @param fileName
     * @return
     */
    String getPath(String prefix, String fileName) {
        String ext = FileUtil.getExt(fileName);
        StringBuilder path = new StringBuilder();
        if (!StringUtils.isEmpty(prefix)) {
            path.append(prefix).append("/");
        }
        String dataPath = DateTimeFormatter.ofPattern("yyyy/MM/dd").format(LocalDateTime.now());
        path.append(dataPath).append("/").append(UUID.randomUUID().toString().replace("-", "")).append(".").append(ext);
        return path.toString();
    }

    /**
     * 初始化之后的操作
     * @param props
     */
    public void afterInitialization(FileStorageProperties props) {
        setProps(props);
    }

    /**
     * 准备客户端
     */
    public void prepareClient(String bucket) {}

    /**
     * 关闭客户端
     */
    public void closeClient() {
        clearStorageClient();
    }

    /**
     * 获取客户端
     * @return
     */
    T getStorageClient() {
        return this.client.get();
    }

    void setStorageClient(T client) {
        this.client.set(client);
    }

    void clearStorageClient() {
        this.client.remove();
    }

    FileStorageProperties getProps() {
        return props;
    }

    private void setProps(FileStorageProperties props) {
        this.props = props;
    }

}
